import { CanvasTexture, Color, Group, Vector2, Vector3 } from "three";
import { CqkjMap } from "../Basic/CqkjMap";
import { MapElement, MapElementOption } from "../Basic/MapElement";
import { PROJECTION, ZERO2 } from "../Util/static";
import { Airport } from "./Airport";
import { Line2 } from "three/examples/jsm/lines/Line2";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry";
import { setValue } from "../Util/common";
import { FixAxisSprite, FixAxisSpriteMaterial } from "../Basic/FixAxisSprite";

const COLORS = [new Color(0x94CCB1), new Color(0x6CF8AC), new Color(0xFFD43A), new Color(0xFF3A3A)]

const matLine = new LineMaterial({
  color: 0xffffff,
  linewidth: 0.002, // in world units with size attenuation, pixels otherwise
  vertexColors: true,
  dashed: false,
  alphaToCoverage: true,
  depthTest: false,
  depthWrite: false,
});


export interface AirLineOption extends MapElementOption {
  points: {
    lon: number
    lat: number
    name: string
  }[];
  risks: number[];
  height: number;
}

export class AirLine extends MapElement<AirLineOption>{

  root = new Group()
  texture: CanvasTexture;

  get show(): boolean {
    return this.option.show
  }
  set show(val: boolean) {
    setValue(this.option, 'show', val, () => {
      this.root.visible = val
    })
  }

  constructor(map: CqkjMap, option: AirLineOption) {
    super(map, option)
    
    const fragments: {
      from: Vector3
      to: Vector3
      risk: number
    }[] = []
    const { root } = this
    root.visible=option.show
    this.texture = createLabelTexture(option.name)
    let before: Vector3
    const z = PROJECTION.altToZ(option.height)
    option.points.forEach((e, i) => {
      const airport = map.elements.get(e.name)
      const point = airport instanceof Airport ? airport.root.position : new Vector3(PROJECTION.lonToX(e.lon), PROJECTION.latToY(e.lat), z)
      if (before) {
        fragments.push({
          from: before,
          to: point,
          risk: option.risks[i - 1]
        })
      }
      before = point
    })
    const positions: number[] = []
    const colors: number[] = [];
    fragments.forEach(e => {
      const { from, to, risk } = e
      const color = COLORS[risk]
      positions.push(from.x, from.y, from.z)
      colors.push(color.r, color.g, color.b);
      const direction = to.clone().sub(from).setZ(0).normalize();
      if (from.z != z) {
        const point = direction.clone().multiplyScalar(10000).add(from).setZ(z);
        positions.push(point.x, point.y, point.z)
        colors.push(color.r, color.g, color.b);
      }
      if (to.z != z) {
        const point = direction.clone().multiplyScalar(10000).sub(to).multiplyScalar(-1).setZ(z);
        positions.push(point.x, point.y, point.z);
        colors.push(color.r, color.g, color.b);
      }
      positions.push(to.x, to.y, to.z);
      colors.push(color.r, color.g, color.b);
      const label = createLabel(this.texture, direction, risk)
      label.position.copy(from).add(to).divideScalar(2).setZ(z)
      root.add(label)
    })
    const geometry = new LineGeometry();
    geometry.setPositions(positions);
    geometry.setColors(colors);
    const line = new Line2(geometry, matLine);
    root.add(line)
    map.scene.add(root);
  }

  focus() {
    const { map, root } = this
    map.zoomTo(root.children[Math.floor(root.children.length/2)].position, 500000)
  }


  onDestroy(): void {
    this.map.scene.add(this.root);
    

  }

}


function createLabelTexture(name: string) {
  const width = name.length * 12 + 2;
  const height = 16;
  const canvas = document.createElement("canvas");
  canvas.width = width;
  canvas.height = height;
  const ctx = canvas.getContext("2d")!;
  ctx.font = "12px OPPOSans";
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  ctx.fillStyle = "#ffffff";
  ctx.fillRect(0, 0, width, height);
  ctx.fillStyle = "#000000";
  ctx.fillText(name, width / 2, height / 2);
  const texture = new CanvasTexture(canvas);
  return texture
}

const CENTER = new Vector2(0.5, 0.5)

function createLabel(texture: CanvasTexture, direction: Vector3, risk: number) {
  const width = texture.image.width;
  const height = texture.image.height;
  return new FixAxisSprite(new FixAxisSpriteMaterial({
    size: ZERO2,
    center: CENTER,
    scale: new Vector2(0.001 * width, 0.001 * height),
    direction,
    axis: "x",
    uniforms: {
      u_texture: {
        value: texture,
      },
      u_color: {
        value: COLORS[risk]
      }
    },
    fragmentShader: /* glsl */ `
    varying vec2 v_uv;
    uniform sampler2D u_texture;
    uniform vec3 u_color;
    void main() {
      gl_FragColor = texture2D(u_texture,v_uv)* vec4(u_color,1.0);
    }
    `,
  }))
}